package com.freecycle.sg.ui;

import java.util.ArrayList;
import java.util.HashMap;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.database.ContentObserver;
import android.database.Cursor;
import android.location.Location;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.app.ListFragment;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CursorAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;

import com.freecycle.sg.R;
import com.freecycle.sg.http.HTTPManager;
import com.freecycle.sg.http.HTTPResponseHandler;
import com.freecycle.sg.sqlite.Freebie.Freebies;
import com.freecycle.sg.sqlite.Freebie.ReferenceData;
import com.freecycle.sg.utils.Config;
import com.freecycle.sg.utils.JSONUtils;
import com.freecycle.sg.utils.NotifyingAsyncQueryHandler;
import com.freecycle.sg.utils.NotifyingAsyncQueryHandler.AsyncQueryListener;
import com.loopj.android.http.RequestParams;

public class FreebieListFragment extends ListFragment implements AsyncQueryListener{
	
	private static final String TAG = "FreebieListFragment";
	
	private static final String STATE_CHECKED_POSITION = "STATE_CHECKED_POSITION";

	private Cursor mCursor;
	private CursorAdapter mAdapter;
	private int mCheckedPosition = -1;
	private boolean mHasSetEmptyText = false;

	private NotifyingAsyncQueryHandler mHandler;

	private HashMap<String, String> mCategories;
	
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setHasOptionsMenu(true);

		mHandler = new NotifyingAsyncQueryHandler(getActivity()
				.getContentResolver(), this);
		mHandler.startQuery(ReferenceQuery._TOKEN, null,
				ReferenceData.CONTENT_URI, 
				ReferenceQuery.projection,
				ReferenceData.REF_DATA_TYPE + "=?", 
				new String[] { Config.REF_CATEGORIES },
				ReferenceData.DEFAULT_SORT);

		reloadFromArguments(getArguments());
	}

	public void reloadFromArguments(Bundle arguments) {
		if (mCursor != null) {
			getActivity().stopManagingCursor(mCursor);
			mCursor = null;
		}

		// Reset checked position and listview's adapter
		mCheckedPosition = -1;
		setListAdapter(null);

		// Abort currently running query if any
		mHandler.cancelOperation(FreebiesQuery._TOKEN);

		// Build intent based on loaded arguments
		final Intent intent = BaseActivity.fragmentArgumentsToIntent(arguments);
		final Location curLocation = intent.getParcelableExtra(Intent.EXTRA_STREAM);

		if (curLocation == null) {
			return;
		}

		// Create new message adapter
		mAdapter = new FreebiesAdapter(getActivity());
		setListAdapter(mAdapter);

		// Load freebies from server
		downloadFreebies(curLocation);
		
		// Load from local database
		mHandler.startQuery(
				FreebiesQuery._TOKEN, 
				null, 
				Freebies.CONTENT_URI, 
				FreebiesQuery.projection,
				null,
				null, 
				Freebies.DEFAULT_SORT);
	}
	
	private void downloadFreebies(Location location) {
		// TODO decode the top left and bottom right corners of the screen cordinates.
		// For now just do the current location cordinates only
		
		RequestParams params = new RequestParams();
		params.put("swLat", String.valueOf(location.getLatitude()));
		params.put("swLng", String.valueOf(location.getLongitude()));
		params.put("neLat", String.valueOf(location.getLatitude() + 0.2d));
		params.put("neLng", String.valueOf(location.getLongitude() + 0.2d));
		
		HTTPResponseHandler handler = new HTTPResponseHandler(getActivity()){
			@Override
			public void onSuccess(JSONObject object) {
				try {
					Log.v(TAG, object.toString(2));
					ContentResolver resolver = getActivity().getContentResolver();
					
					// Delete all the records from local database
					resolver.delete(Freebies.CONTENT_URI, null, null);
					
					// Load all record into local database
					ArrayList<ContentValues> values = new ArrayList<ContentValues>();
					JSONArray messages = object.getJSONArray("freebies");
					
					for (int i = 0; i < messages.length(); i++) {
						JSONObject temp = messages.getJSONObject(i);
						values.add(JSONUtils.buildFreebieCv(temp));
					}
					
					resolver.bulkInsert(Freebies.CONTENT_URI, values.toArray(new ContentValues[]{}));
					resolver.notifyChange(Freebies.CONTENT_URI, null);
				} catch (JSONException e) {
					Log.e(TAG, e.toString());
				}
			}
		};
		
		HTTPManager.post(Config.getFreebiesUri, null, handler);
	}

	@Override
	public void onActivityCreated(Bundle savedInstanceState) {
		super.onActivityCreated(savedInstanceState);
		getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);

		if (savedInstanceState != null) {
			mCheckedPosition = savedInstanceState.getInt(
					STATE_CHECKED_POSITION, -1);
		}

		if (!mHasSetEmptyText) {
			// Could be a bug, but calling this twice makes it become visible
			// when it shouldn't be visible.
			setEmptyText(getString(R.string.no_message));
			mHasSetEmptyText = true;
		}
	}

	@Override
	public void onResume() {
		super.onResume();
		getActivity().getContentResolver().registerContentObserver(
				Freebies.CONTENT_URI, true, mFreebiesChangesObserver);
		if (mCursor != null) {
			mCursor.requery();
		}
	}

	@Override
	public void onPause() {
		super.onPause();
		getActivity().getContentResolver().unregisterContentObserver(
				mFreebiesChangesObserver);
	}

	@Override
	public void onSaveInstanceState(Bundle outState) {
		super.onSaveInstanceState(outState);
		outState.putInt(STATE_CHECKED_POSITION, mCheckedPosition);
	}
	
	@Override
	public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
		inflater.inflate(R.menu.back_menu_items, menu);
		inflater.inflate(R.menu.add_menu_items, menu);
		super.onCreateOptionsMenu(menu, inflater);
	}
	
	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		if (item.getItemId() == R.id.menu_back) {
			getActivity().onBackPressed();
			return true;
		} else if (item.getItemId() == R.id.menu_add) {
			final Intent intent = new Intent(Intent.ACTION_INSERT);
	        intent.setType(Freebies.CONTENT_ITEM_TYPE);
			getActivity().startActivity(intent);
			return true;
		}
		return super.onOptionsItemSelected(item);
	}

	@Override
	public void onQueryComplete(int token, Object cookie, Cursor cursor) {
		if (getActivity() == null) {
			return;
		}

		if (token == FreebiesQuery._TOKEN) {
			if (mCursor != null) {
				getActivity().stopManagingCursor(mCursor);
				mCursor = null;
			}

			mCursor = cursor;
			getActivity().startManagingCursor(mCursor);
			
			if (mCursor != null) {
				mAdapter.changeCursor(mCursor);
				Log.v(TAG, "count cursor " + mCursor.getCount());
			}

			if (mCheckedPosition >= 0 && getView() != null) {
				getListView().setItemChecked(mCheckedPosition, true);
			}
			
		} else if (token == ReferenceQuery._TOKEN) {
			getActivity().stopManagingCursor(cursor);
			
			mCategories = new HashMap<String, String>();
			
			if (cursor.moveToFirst()) {
				do {
					String key = cursor.getString(ReferenceQuery.ABBREVIATION);
					String value = cursor.getString(ReferenceQuery.NAME);
					mCategories.put(key, value);
				} while (cursor.moveToNext());
			}
		} else {
			cursor.close();
		}
	}

	/** {@inheritDoc} */
	@Override
	public void onListItemClick(ListView l, View v, int position, long id) {
		// Get reference of clicked freebie
		final Cursor cursor = (Cursor) mAdapter.getItem(position);
		final String freebieId = cursor.getString(FreebiesQuery.FREEBIE_ID);
		final Uri freebieUri = Freebies.buildFreebieUri(freebieId);

		final Intent intent = new Intent(Intent.ACTION_VIEW, freebieUri);
		((BaseActivity) getActivity()).openActivityOrFragment(intent);

		getListView().setItemChecked(position, true);
		mCheckedPosition = position;
	}

	/**
	 * Register this observer to listen for local database changes
	 */
	private ContentObserver mFreebiesChangesObserver = new ContentObserver(
			new Handler()) {
		@Override
		public void onChange(boolean selfChange) {
			if (mCursor != null) {
				mCursor.requery();
			}
		}
	};

	public void clearCheckedPosition() {
		if (mCheckedPosition >= 0) {
			getListView().setItemChecked(mCheckedPosition, false);
			mCheckedPosition = -1;
		}
	}

	/** Customized adapter to display each list item */
	private class FreebiesAdapter extends CursorAdapter {

		public FreebiesAdapter(Context context) {
			super(context, null);
		}

		@Override
		public void bindView(View view, Context context, Cursor cursor) {
			final ImageView image = (ImageView) view
					.findViewById(R.id.image);
			final TextView title = (TextView) view
					.findViewById(R.id.title);
			final TextView address = (TextView) view
					.findViewById(R.id.address);
			final TextView description = (TextView) view
					.findViewById(R.id.description);
			final TextView category = (TextView) view
					.findViewById(R.id.category);

			title.setText(cursor.getString(FreebiesQuery.TITLE));
			address.setText(cursor.getString(FreebiesQuery.FORMATTED_ADDRESS));
			description.setText(cursor.getString(FreebiesQuery.DESCRIPTION));
			category.setText(mCategories.get(cursor.getString(FreebiesQuery.CATEGORY)));
			
			// TODO currently just set the no listing image
			image.setImageResource(R.drawable.no_image_listing);
		}

		@Override
		public View newView(Context context, Cursor cursor, ViewGroup parent) {
			return getActivity().getLayoutInflater().inflate(
					R.layout.list_item_freebie, parent, false);
		}

	}

	/*private class EndlessScrollListener implements OnScrollListener {

		private int visibleThreshold = 3;
		private int previousTotal = 0;
		private int currentPage = 1;
		private boolean loading = true;

		public EndlessScrollListener(int visibleThreshold) {
			this.visibleThreshold = visibleThreshold;
		}

		@Override
		public void onScroll(AbsListView view, int firstVisibleItem,
				int visibleItemCount, int totalItemCount) {
			if (loading) {
				if (totalItemCount > previousTotal) {
					loading = false;
					previousTotal = totalItemCount;
					currentPage++;
				}
			}

			if (!loading && (totalItemCount - visibleItemCount) <= (firstVisibleItem + visibleThreshold)) {
				Log.v(TAG, "Load the next page of listings here. Page " + currentPage);

				if (currentTab == 0) {
					AgentHelper.loadInboxMessage((BaseActivity) getActivity(),
							String.valueOf(currentPage));
				} else if (currentTab == 1) {
					AgentHelper.loadArchiveMessage(
							(BaseActivity) getActivity(),
							String.valueOf(currentPage));
				}

				loading = true;
			}
		}

		@Override
		public void onScrollStateChanged(AbsListView view, int scrollState) {
		}
	}*/

	/** {@link FreebiesAdapter} query parameters. */
	private interface FreebiesQuery {
		int _TOKEN = 0x1;

		String[] projection = { Freebies._ID, 
				Freebies.FREEBIE_ID,
				Freebies.ADDED, 
				Freebies.LATITUDE,
				Freebies.LONGITUDE, 
				Freebies.FORMATTED_ADDRESS, 
				Freebies.TITLE, 
				Freebies.DESCRIPTION,
				Freebies.CATEGORY,
				};
		
		int FREEBIE_ID = 1;
		/*int ADDED = 2;
		int LATITUDE = 3;
		int LONGITUDE = 4;*/
		int FORMATTED_ADDRESS = 5;
		int TITLE = 6;
		int DESCRIPTION = 7;
		int CATEGORY = 8; 
	}
	
	private interface ReferenceQuery {
		int _TOKEN = 0x232;

		String[] projection = { 
				ReferenceData._ID,
				ReferenceData.REF_DATA_TYPE,
				ReferenceData.ABBREVIATION,
				ReferenceData.NAME,
				ReferenceData.MARKER_URL,
				};
		
		int REF_DATA_TYPE = 1;
		int ABBREVIATION = 2;
		int NAME = 3;
		int MARKER_URL = 4;
	}

}
